"""
Redis工具适配层
为了兼容现有代码，提供与原来相同的函数接口
"""
from typing import List, Dict, Optional, Any
import json
from app.utils.redis_utils import redis_utils
from app.config.redis import redis_client

# Redis键名定义类
class RedisKeys:
    """Redis键名常量定义"""
    # 视频相关键名（与node-server-api-summary.md一致）
    VIDEO_DETAIL = 'video:detail:{video_id}'
    VIDEO_RECOMMENDED_ZSET = 'videos:recommended:zset'
    VIDEO_HOT_ZSET = 'videos:hot:zset'
    VIDEO_LATEST_PAGE = 'videos:latest:page:{page}:size:{pageSize}'
    VIDEO_SLIDE = 'videos:slide'
    VIDEO_CATEGORY_PAGE = 'videos:category:{categoryId}:page:{page}:size:{pageSize}'
    
    # 布隆过滤器键名
    BLOOM_FILTER_VIDEO = 'bf:video:exists'
    
    # 计数器键名
    VIDEO_VIEW_COUNT = 'video:view:count:{video_id}'
    
    # 队列键名
    VIDEO_VIEW_UPDATE_QUEUE = 'video:view:update:queue'

# 缓存过期时间定义类
class CacheExpiry:
    # 缓存过期时间（秒）
    VIDEO_DETAIL = 3600  # 1小时
    VIDEO_RECOMMENDED_ZSET = 3600  # 1小时
    VIDEO_HOT_ZSET = 3600  # 1小时
    VIDEO_LATEST_PAGE = 1800  # 30分钟，较短
    VIDEO_SLIDE = 3600  # 1小时
    VIDEO_CATEGORY_PAGE = 1800  # 30分钟，较短
    VIDEO_VIEW_COUNT = 86400  # 24小时

# 直接返回redis_client
def get_client():
    """获取Redis客户端实例"""
    return redis_client

# 通用缓存操作函数
def get_cache(key: str) -> Optional[Any]:
    """获取缓存数据"""
    try:
        # 尝试根据键名模式使用对应的方法
        if key.startswith('video:detail:'):
            video_id = key.split(':')[-1]
            return redis_utils.get_cached_video_detail(int(video_id))
        elif key.startswith('videos:latest:page:'):
            return redis_utils.get_cached_new_videos()
        elif key.startswith('videos:hot:'):
            return redis_utils.get_cached_hot_videos()
        elif key == 'videos:slide':
            return redis_utils.get_cached_slide_videos()
        elif key.startswith('videos:recommended:'):
            return redis_utils.get_cached_recommend_videos()
        elif key.startswith('videos:category:'):
            return redis_utils.get_cached_category_videos()
        
        # 默认直接从Redis获取
        data = redis_client.get(key)
        return json.loads(data) if data else None
    except Exception as e:
        print(f"获取缓存失败 [{key}]: {str(e)}")
        return None

def set_cache(key: str, value: Any, expire: int = 3600) -> bool:
    """设置缓存数据"""
    try:
        # 尝试根据键名模式使用对应的方法
        if key.startswith('video:detail:'):
            video_id = key.split(':')[-1]
            redis_utils.cache_video_detail(int(video_id), value)
            return True
        elif key.startswith('videos:latest:page:'):
            redis_utils.cache_new_videos(value)
            return True
        elif key.startswith('videos:hot:'):
            redis_utils.cache_hot_videos(value)
            return True
        elif key == 'videos:slide':
            redis_utils.cache_slide_videos(value)
            return True
        elif key.startswith('videos:recommended:'):
            redis_utils.cache_recommend_videos(value)
            return True
        elif key.startswith('videos:category:'):
            redis_utils.cache_category_videos(value)
            return True
        
        # 默认直接设置到Redis
        redis_client.setex(key, expire, json.dumps(value))
        return True
    except Exception as e:
        print(f"设置缓存失败 [{key}]: {str(e)}")
        return False

def delete_cache(key: str) -> bool:
    """删除缓存数据"""
    try:
        return redis_client.delete(key) > 0
    except Exception as e:
        print(f"删除缓存失败 [{key}]: {str(e)}")
        return False

def delete_cache_pattern(pattern: str) -> int:
    """根据模式删除缓存"""
    try:
        keys = redis_client.keys(pattern)
        if keys:
            return redis_client.delete(*keys)
        return 0
    except Exception as e:
        print(f"删除缓存模式失败 [{pattern}]: {str(e)}")
        return 0

def get_cached_category_videos(category_id, page=1, page_size=10):
    """获取分类视频缓存
    
    Args:
        category_id: 分类ID
        page: 页码
        page_size: 每页数量
    
    Returns:
        缓存的视频列表，如果不存在返回None
    """
    try:
        from app.utils.redis_util import RedisKeys
        cache_key = f"{RedisKeys.VIDEO_CATEGORY_ZSET}:{category_id}:{page}:{page_size}"
        return get_cache(cache_key)
    except Exception as e:
        logger.error(f"获取分类视频缓存失败: {e}, category_id={category_id}")
        return None

def increment_counter(key: str) -> int:
    """增加计数器值"""
    try:
        return redis_client.incr(key)
    except Exception as e:
        print(f"增加计数器失败 [{key}]: {str(e)}")
        return 0

def exists(key: str) -> bool:
    """检查键是否存在"""
    try:
        return redis_client.exists(key) > 0
    except Exception as e:
        print(f"检查键存在失败 [{key}]: {str(e)}")
        return False

# 布隆过滤器相关函数
def add_to_bloom_filter(key: str) -> bool:
    """添加到布隆过滤器"""
    # 简化实现，实际应该使用布隆过滤器
    try:
        return redis_client.set(f'bf:{key}', 1, ex=86400)  # 1天过期
    except Exception as e:
        print(f"添加布隆过滤器失败 [{key}]: {str(e)}")
        return False

def check_bloom_filter(key: str, value) -> bool:
    """
    检查元素是否在布隆过滤器中
    
    Args:
        key: 布隆过滤器键名
        value: 要检查的元素
        
    Returns:
        bool: True表示可能存在，False表示一定不存在
    """
    try:
        return redis_client.exists(key, value)
    except Exception as e:
        logger.error(f"检查布隆过滤器失败: {e}")
        return False

# 观看次数更新队列
def queue_view_count_update(video_id: int) -> bool:
    """将视频观看次数更新加入队列"""
    try:
        # 使用Redis List作为队列，将视频ID添加到队列尾部
        redis_client.lpush('video:view:update:queue', video_id)
        
        # 同时确保更新Redis中的计数器
        video_key = f'video:view:count:{video_id}'
        redis_client.incr(video_key)
        return True
    except Exception as e:
        print(f"队列更新观看次数失败 [{video_id}]: {str(e)}")
        return False

def is_allowed(key: str) -> bool:
    """检查是否允许操作（限流等）"""
    try:
        return not redis_client.exists(f'limit:{key}')
    except Exception as e:
        print(f"检查允许操作失败 [{key}]: {str(e)}")
        return True

# ZSET操作函数
def get_zset_range(key: str, start: int, end: int) -> List[str]:
    """获取ZSET范围内的数据"""
    try:
        return redis_client.zrange(key, start, end)
    except Exception as e:
        print(f"获取ZSET范围失败 [{key}]: {str(e)}")
        return []

def zadd(key: str, mapping: Dict[str, float]) -> int:
    """添加数据到ZSET"""
    try:
        return redis_client.zadd(key, mapping)
    except Exception as e:
        print(f"添加ZSET数据失败 [{key}]: {str(e)}")
        return 0
